# NullAwarePreparedStatementWriter.java

    package org.codefilarete.stalactite.sql.statement.binder;

    import java.sql.PreparedStatement;
    import java.sql.SQLException;

    import org.codefilarete.tool.function.SerializableThrowingTriConsumer;

    /**
     * Wrapper around another {@link PreparedStatementWriter} to handle null value
     *
     * @author Guillaume Mary
     */
    public class NullAwarePreparedStatementWriter<T> implements PreparedStatementWriter<T> {

    	private final PreparedStatementWriter<T> delegate;

    	public NullAwarePreparedStatementWriter(SerializableThrowingTriConsumer<PreparedStatement, Integer, T, SQLException> preparedStatementSetter) {
    		this(PreparedStatementWriter.ofMethodReference(preparedStatementSetter));
    	}

    	public NullAwarePreparedStatementWriter(PreparedStatementWriter<T> delegate) {
    		this.delegate = delegate;
    	}

    	@Override
    	public void set(PreparedStatement statement, int valueIndex, T value) throws SQLException {
    		if (value == null) {
    			setNull(valueIndex, statement);
    		} else {
    			setNotNull(valueIndex, value, statement);
    		}
    	}

    	@Override
    	public Class<T> getType() {
    		return delegate.getType();
    	}

    	/**
    	 * Special method for null values.
    	 * This implementation is based on {@link PreparedStatement#setObject(int, Object)} with null as 2nd argument, but not all JDBC drivers
    	 * support this way of doing and shall need usage of {@link PreparedStatement#setNull(int, int)}. So this method is here to be overridden
    	 * according to support of setObject(int, null).
    	 *
    	 * @param valueIndex the index where to set null, first argument of setXXX(..)
    	 * @param statement the {@link PreparedStatement} on which to set null
    	 * @throws SQLException the possible error thrown by {@link PreparedStatement#setObject(int, Object)}
    	 */
    	protected void setNull(int valueIndex, PreparedStatement statement) throws SQLException {
    		// could be : statement.setNull(valueIndex, statement.getParameterMetaData().getParameterType(valueIndex))
    		statement.setObject(valueIndex, null);
    	}

    	public void setNotNull(int valueIndex, T value, PreparedStatement statement) throws SQLException {
    		delegate.set(statement, valueIndex, value);
    	}
    }